#include "math.h"
#include "timer.h"
#include "GPGPU_FFT.h"

class GPGPU_FFT_Manager;

list<Error_Msg> error_messages_v;
list<Error_Msg> error_messages_p;

static float *get_sample_data(DataDesc *dd) {
  /* use mock data now */
  unsigned int data_size = dd->projection*dd->height*dd->width;
  float *sample_data = (float *)malloc(data_size*sizeof(float));
  int i,j,k,index_base;
  for( i=0;i<dd->projection;i++) {
	  for( j=0; j<dd->height; j++) {
		  index_base = (i*dd->height+j)*dd->width;
		  for( k=0;k<dd->width;k++) {
			sample_data[index_base+k] = (float)(k+1);
		  }
	  }
  }
  return sample_data;
}


static DataDesc *read_desc_file(char *desc_file_name) {
	//TODO: read from file
	//DataDesc *dd = new DataDesc(360, 256, 256);
	DataDesc *dd = new DataDesc(360, 256, 256);
	//DataDesc *dd = new DataDesc(360, 1, 256);
	return dd;
}

static float *read_data_file(DataDesc *dd, char *file_name) {
	int data_size = dd->projection*dd->height*dd->width;
    float *input_data = (float *)malloc(data_size*sizeof(float));
	FILE *data_file;
	fopen_s(&data_file,file_name,"rb");
	fread(input_data, sizeof(float), data_size, data_file);
	fclose(data_file);
	return input_data;
}


static void gpu_run(float *data, float*output, DataDesc *data_desc) {
	CPerfCounter timer;
	GPGPU_FFT_Manager fft_Manager(data_desc);

	cout<<"device init..."<<endl;
	timer.Start();
	if(!fft_Manager.gpgpu_init()) {
		cout<<"GPGPU init error... "<<endl;
		return;
	}
	fft_Manager.gpgpu_init_const();
	timer.Stop();
	double init_time = timer.GetElapsedTime();
	timer.Reset();

	cout<<"running..."<<endl;
	timer.Start();
	//fft_Manager.gpgpu_iterative_run(data, output);
	fft_Manager.gpgpu_synchronized_pinned_run(data, output);
	timer.Stop();
	double run_time = timer.GetElapsedTime();
	timer.Reset();

	cout<<"write back..."<<endl;
	timer.Start();
	fft_Manager.gpgpu_exit();
	timer.Stop();
	double back_time = timer.GetElapsedTime();
	timer.Reset();

	cout<<"device init: "<<init_time<<" s"<<endl;
	cout<<"run: "<<run_time<<" s"<<endl;
	cout<<"exit: "<<back_time<<" s"<<endl;
	cout<<"================="<<endl;
}

static void cpu_run(float *data, DataDesc *data_desc) {
	CPerfCounter timer;
	cout << "perform FFT on CPU..." << endl;
	timer.Start();
	unsigned int height = data_desc->projection*data_desc->height;
	CPU_FFT_Manager cpu_manager(data_desc);
	cpu_manager.cpu_run(data);
	timer.Stop();
    cout << "CPU FFT time: " <<timer.GetElapsedTime()<<endl;
    timer.Reset();
	float *result = cpu_manager.get_result();
	//dump_result(result);
	unsigned int size = data_desc->height*data_desc->projection*data_desc->width;
	FILE *out;
	fopen_s(&out,"gpu.dat","wb");
	fwrite(result,sizeof(float),size,out);
	fclose(out);
}

/*
void compare_by_percent(float *dataset1, float *dataset2, unsigned int length, unsigned int raw) {
  unsigned int i = 0;
  for(;i<length;i++) {
	  float rate = fabs((dataset1[i] -dataset2[i])/dataset1[i]);
	  if(rate>ERROR_THRESHOLD_P) {
		  int raw_num = i/COMPLEX_MATRIX_W;
		  int col_num = i%COMPLEX_MATRIX_W;
		  error_messages_p.push_back(Error_Msg(raw_num, col_num, dataset1[i], dataset2[i], rate));
	  }
  }
}

void compare_by_value(float *dataset1, float *dataset2, unsigned int length, unsigned int raw) {
  unsigned int i = 0;
  for(;i<length;i++) {
	  float diff = fabs(dataset1[i] -dataset2[i]);
	  if(diff>ERROR_THRESHOLD_V) {
		   int raw_num = i/COMPLEX_MATRIX_W;
		  int col_num = i%COMPLEX_MATRIX_W;
		  error_messages_p.push_back(Error_Msg(raw_num, col_num, dataset1[i], dataset2[i], diff));
	  }
  }
}
*/

/*
static unsigned int switch_sheet1 [] = {
	0, 1024, 512, 1536, 256, 1280, 768, 1792, 128, 1152, 640, 1664, 384, 1408, 896, 1920, 64, 1088, 576, 1600, 320, 1344, 832, 1856, 192, 1216, 704, 1728, 448, 1472, 960, 1984, 0, 1056, 544, 1568, 288, 1312, 800, 1824, 160, 1184, 672, 1696, 416, 1440, 928, 1952, 96, 1120, 608, 1632, 352, 1376, 864, 1888, 224, 1248, 736, 1760, 480, 1504, 992, 2016, 16, 1040, 528, 1552, 272, 1296, 784, 1808, 144, 1168, 656, 1680, 400, 1424, 912, 1936, 0, 1104, 592, 1616, 336, 1360, 848, 1872, 208, 1232, 720, 1744, 464, 1488, 976, 2000, 48, 1072, 560, 1584, 304, 1328, 816, 1840, 176, 1200, 688, 1712, 432, 1456, 944, 1968, 0, 1136, 624, 1648, 368, 1392, 880, 1904, 240, 1264, 752, 1776, 496, 1520, 1008, 2032, 8, 1032, 520, 1544, 264, 1288, 776, 1800, 0, 1160, 648, 1672, 392, 1416, 904, 1928, 72, 1096, 584, 1608, 328, 1352, 840, 1864, 200, 1224, 712, 1736, 456, 1480, 968, 1992, 40, 1064, 552, 1576, 296, 1320, 808, 1832, 0, 1192, 680, 1704, 424, 1448, 936, 1960, 104, 1128, 616, 1640, 360, 1384, 872, 1896, 232, 1256, 744, 1768, 488, 1512, 1000, 2024, 24, 1048, 536, 1560, 280, 1304, 792, 1816, 152, 1176, 664, 1688, 408, 1432, 920, 1944, 88, 1112, 600, 1624, 344, 1368, 856, 1880, 0, 1240, 728, 1752, 472, 1496, 984, 2008, 56, 1080, 568, 1592, 312, 1336, 824, 1848, 184, 1208, 696, 1720, 440, 1464, 952, 1976, 120, 1144, 632, 1656, 376, 1400, 888, 1912, 0, 1272, 760, 1784, 504, 1528, 1016, 2040, 4, 1028, 516, 1540, 0, 1284, 772, 1796, 132, 1156, 644, 1668, 388, 1412, 900, 1924, 68, 1092, 580, 1604, 324, 1348, 836, 1860, 196, 1220, 708, 1732, 452, 1476, 964, 1988, 36, 1060, 548, 1572, 0, 1316, 804, 1828, 164, 1188, 676, 1700, 420, 1444, 932, 1956, 100, 1124, 612, 1636, 356, 1380, 868, 1892, 228, 1252, 740, 1764, 484, 1508, 996, 2020, 20, 1044, 532, 1556, 276, 1300, 788, 1812, 148, 1172, 660, 1684, 404, 1428, 916, 1940, 84, 1108, 596, 1620, 0, 1364, 852, 1876, 212, 1236, 724, 1748, 468, 1492, 980, 2004, 52, 1076, 564, 1588, 308, 1332, 820, 1844, 180, 1204, 692, 1716, 436, 1460, 948, 1972, 116, 1140, 628, 1652, 0, 1396, 884, 1908, 244, 1268, 756, 1780, 500, 1524, 1012, 2036, 12, 1036, 524, 1548, 268, 1292, 780, 1804, 140, 1164, 652, 1676, 0, 1420, 908, 1932, 76, 1100, 588, 1612, 332, 1356, 844, 1868, 204, 1228, 716, 1740, 460, 1484, 972, 1996, 44, 1068, 556, 1580, 300, 1324, 812, 1836, 172, 1196, 684, 1708, 0, 1452, 940, 1964, 108, 1132, 620, 1644, 364, 1388, 876, 1900, 236, 1260, 748, 1772, 492, 1516, 1004, 2028, 28, 1052, 540, 1564, 284, 1308, 796, 1820, 156, 1180, 668, 1692, 412, 1436, 924, 1948, 92, 1116, 604, 1628, 348, 1372, 860, 1884, 220, 1244, 732, 1756, 0, 1500, 988, 2012, 60, 1084, 572, 1596, 316, 1340, 828, 1852, 188, 1212, 700, 1724, 444, 1468, 956, 1980, 124, 1148, 636, 1660, 380, 1404, 892, 1916, 252, 1276, 764, 1788, 0, 1532, 1020, 2044
};

for(int i=0;i<512;i++) {
		if(switch_sheet1[i] && switch_sheet1[i]<512) {
			int j = switch_sheet1[i];
			if(!switch_sheet1[j])
				printf("%d should be %d", j, i);
		}
}
*/

int main(int args, char *argv[]) {

	/*
	DataDesc *dd = read_desc_file(argv[2]);
	float *file_data = read_data_file(dd, argv[1]);
	gpu_run(file_data, dd);
	*/

	DataDesc *dd = new DataDesc(360, 512, 512);
	unsigned int data_size = dd->projection*dd->height*dd->width;
	float *output = (float *)malloc(data_size*sizeof(float));

	float *sample_data = get_sample_data(dd);
    gpu_run(sample_data, output, dd);
	//cpu_run(sample_data, dd);


	/*
	DataDesc *dd = read_desc_file(argv[2]);
	float *file_data = read_data_file(dd, argv[1]);
	cpu_run(file_data, dd);
	free(dd);
	free(file_data);
	*/
	
	
	/*
	run_single();
	*/

}
